package com.example.kotlindemo.modules.network

import android.util.Log
import com.example.kotlindemo.utils.ApiClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import retrofit2.Response

// 定义一个通用的资源类来包装数据状态
sealed class Resource<out T> {
    data object Loading : Resource<Nothing>() // 加载中状态
    data class Success<out T>(val data: T) : Resource<T>() // 成功状态，包含数据
    data class Error(val message: String, val code: Int? = null) : Resource<Nothing>() // 失败状态，包含错误信息和可选的状态码
}

class LoginRepository {

    private val apiService = ApiClient.apiService // 获取 ApiService 实例

    // 使用 Flow 来发射登录结果状态
    fun login(params: LoginParams): Flow<Resource<UserResponse>> = flow {
        // 1. 发射 Loading 状态
        emit(Resource.Loading)

        // 2. 执行网络请求 (Retrofit suspend 函数)
        val response: Response<BaseResponse<UserResponse>> = apiService.login(params)

        // 3. 处理响应
        if (response.isSuccessful) {
            val body = response.body()
            if (body != null && body.success && body.data != null) {
                // 业务成功，发射 Success 状态
                emit(Resource.Success(body.data))
            } else {
                // 业务失败 (API 返回 success: false 或 data 为 null)
                emit(Resource.Error(body?.message ?: "登录失败，响应数据格式错误"))
            }
        } else {
            // HTTP 请求失败 (状态码非 2xx)
            val errorMsg = response.errorBody()?.string() ?: "未知网络错误"
            Log.e("LoginRepository", "登录请求失败: Code=${response.code()}, Message=$errorMsg")
            emit(Resource.Error("登录请求失败: ${response.code()}", response.code()))
        }
    }.catch { e ->
        // 4. 捕获流中发生的异常 (如网络连接问题、JSON 解析错误等)
        Log.e("LoginRepository", "登录流程异常: ${e.message}", e)
        emit(Resource.Error("登录时发生错误: ${e.localizedMessage ?: "未知异常"}"))
    }.flowOn(Dispatchers.IO) // 5. 指定上游操作（网络请求）在 IO 线程执行

    // --- Flow 的用法和特点讲解 ---
    // 1. Flow 是什么？
    //    - Flow 是 Kotlin Coroutines 提供的一种处理异步数据流（stream of values）的类型。
    //    - 它可以按顺序发射（emit）零个或多个值。
    //    - 它是“冷”的（Cold Stream）：意味着只有当有收集器（collector）开始收集（collect）时，Flow 内部的代码块（flow { ... }）才会执行。每次收集都会重新执行。
    //
    // 2. `flow { ... }` 构建器：
    //    - 这是创建 Flow 最基本的方式。大括号内的代码运行在协程中。
    //    - `emit(value)`: 在 Flow 中发射一个值。可以多次调用 `emit` 来发射多个值。
    //
    // 3. `collect { ... }` 终端操作符：
    //    - 用于启动 Flow 并接收其发射的值。`collect` 是一个挂起函数，它会一直运行直到 Flow 完成。
    //    - 在 ViewModel 中我们会调用 `collect` 来接收 Repository 发射的 `Resource` 状态。
    //
    // 4. `catch { ... }` 操作符：
    //    - 用于捕获 Flow 上游（在 `catch` 之前的操作）发生的异常。
    //    - 它允许你优雅地处理错误，例如发射一个 `Resource.Error` 状态，而不是让异常崩溃应用。
    //    - 注意：它无法捕获下游（`collect` 代码块内部）的异常。
    //
    // 5. `flowOn(Dispatcher)` 操作符：
    //    - 用于改变 Flow 上游操作执行的协程上下文（通常是切换线程池）。
    //    - `flowOn(Dispatchers.IO)` 是一个常见的用法，确保网络请求、数据库读写等阻塞性 IO 操作在后台线程执行，避免阻塞主线程。
    //    - 它只影响 `flowOn` 之前的操作符的执行上下文。下游操作（如 `collect`）仍然在调用 `collect` 的那个协程的上下文中执行（通常是主线程，如果从 `viewModelScope.launch` 启动且未切换）。
    //
    // 6. 为什么用 Flow 而不是直接返回 suspend fun 的结果？
    //    - Flow 可以轻松地发射多个状态。在这个例子中，我们先发射 `Loading`，然后是 `Success` 或 `Error`。这对于向 UI 展示加载状态非常有用。
    //    - Flow 提供了丰富的操作符（map, filter, retry, combine 等），可以方便地对数据流进行转换和处理。
    //    - Flow 与协程无缝集成，遵循结构化并发。
}